package com.iflytek.jcy.supervise.clue.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.iflytek.jcy.supervise.clue.common.constants.AppConstants;
import com.iflytek.jcy.supervise.clue.common.enums.ResultEnum;
import com.iflytek.jcy.supervise.clue.common.enums.TaskEnum;
import com.iflytek.jcy.supervise.clue.common.exception.BaseException;
import com.iflytek.jcy.supervise.clue.common.pojo.CommonResponse;
import com.iflytek.jcy.supervise.clue.component.httpinterface.ModelHttpInterface;
import com.iflytek.jcy.supervise.clue.component.httpinterface.XxlJobHttpInterface;
import com.iflytek.jcy.supervise.clue.component.httpinterface.param.XxlJobInfo;
import com.iflytek.jcy.supervise.clue.component.httpinterface.result.ReturnT;
import com.iflytek.jcy.supervise.clue.entity.*;
import com.iflytek.jcy.supervise.clue.mapper.ClueMapper;
import com.iflytek.jcy.supervise.clue.mapper.TaskLogMapper;
import com.iflytek.jcy.supervise.clue.mapper.TaskMapper;
import com.iflytek.jcy.supervise.clue.service.TaskService;
import com.iflytek.jcy.supervise.clue.web.vo.UapUserInfoVo;

import cn.dev33.satoken.stp.StpUtil;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/** <br>
 * 标题:任务相关服务实现类 <br>
 * 描述: <br>
 * 公司: www.iflytek.com<br>
 * 
 * @autho dgyu
 * @time 2022年10月19日 下午4:22:30 */
@Service
public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements TaskService {

	private static final Logger			 logger	= LoggerFactory.getLogger(TaskServiceImpl.class);
	@Resource
	private TaskMapper					 taskMapper;
	@Resource
	private TaskLogMapper				 taskLogMapper;
	@Resource
	private XxlJobHttpInterface			 xxlJobHttpInterface;
	@Resource
	private XxlJobInfo					 xxlJobInfo;
	public static final SimpleDateFormat sdf	= new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
	public static final SimpleDateFormat sdf2	= new SimpleDateFormat("yyyyMMdd.HHmmss");
	@Resource
	private ModelHttpInterface			 modelHttpInterface;
	@Resource
	private ClueMapper					 clueMapper;
	@Override
	@Transactional(rollbackFor = Exception.class)
	public CommonResponse addTask(TaskEntity taskEntity, HttpServletRequest request) {
		try {
			if (taskEntity.getDatasetId() == null || taskEntity.getDatasetId() <= 0) {
				return CommonResponse.failed("数据集ID不能为空!");
			}
			if (taskEntity.getModelId() == null || taskEntity.getModelId() <= 0) {
				return CommonResponse.failed("模型ID不能为空!");
			}
			if (taskEntity.getType() == 2) {
				if (taskEntity.getFrequency() == null || taskEntity.getFrequency() <= 0) {
					return CommonResponse.failed("任务执行频率不能为空!");
				}
				if (taskEntity.getUnit() == null || taskEntity.getUnit() <= 0) {
					return CommonResponse.failed("任务执行频率单位不能为空!");
				}
			}
			if (taskEntity.getType() == 1 && StringUtils.isNotEmpty(taskEntity.getTaskStartTime()) && sdf.parse(taskEntity.getTaskStartTime()).getTime() < new Date().getTime()) {
				return CommonResponse.failed(ResultEnum.TIME_IS_OUT_DATE);
			}
			this.createTaskName(taskEntity);
			// 任务名称唯一性校验
			LambdaQueryWrapper<Task> lambdaQueryWrapper = new LambdaQueryWrapper<>();
			lambdaQueryWrapper.eq(Task::getTaskName, taskEntity.getTaskName());
			if (this.taskMapper.selectCount(lambdaQueryWrapper) > 0) {
				return CommonResponse.failed(ResultEnum.TASK_NAME_IS_EXIST);
			}
			String cron = this.getCron(taskEntity);
			Task task = new Task();
			BeanUtils.copyProperties(taskEntity, task);
			task.setCron(cron);

			Object user = StpUtil.getSession().get(AppConstants.LOGIN_USER_KEY);
			UapUserInfoVo uapUserInfoVo = (UapUserInfoVo) user;
			task.setCreateLoginId(uapUserInfoVo.getId());
			task.setCreateLoginName(uapUserInfoVo.getName());

			task.setCreateTime(sdf.format(new Date()));
			task.setTaskStatus(TaskEnum.TASK_STATUS_RUNNING.getCode());
			int resultNum = this.baseMapper.insert(task);
			// task.setCanDelete(true);
			if (resultNum > 0) {
				Integer taskId = task.getId();
				xxlJobInfo.setJobDesc(taskEntity.getTaskName());
				xxlJobInfo.setAuthor("线索管理平台");
				xxlJobInfo.setScheduleConf(cron);
				JSONObject jSONObject = new JSONObject();
				jSONObject.put("taskId", taskId);
				if (StringUtils.isNotEmpty(taskEntity.getTaskStartTime())) {
					jSONObject.put("taskStartTime", taskEntity.getTaskStartTime());
				}
				String excuteParam = JSON.toJSONString(jSONObject);
				xxlJobInfo.setExecutorParam(excuteParam);
				logger.info("调用xxl任务注册参数：{}", JSON.toJSONString(xxlJobInfo));
				ReturnT<String> result = this.xxlJobHttpInterface.myadd(xxlJobInfo);
				if (result.getCode() == 200) {
					String xxlTaskId = result.getContent();
					// 更新表数据xxl_task_id
					LambdaUpdateWrapper<Task> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
					lambdaUpdateWrapper.set(Task::getXxlTaskId, xxlTaskId).set(Task::getUpdateTime, new Date()).eq(Task::getId, taskId);
					this.taskMapper.update(null, lambdaUpdateWrapper);
					// 启动服务
					result = this.xxlJobHttpInterface.mystart(Integer.parseInt(xxlTaskId));
					if (result.getCode() != 200) {
						logger.error("启动xll-job任务失败，xxlTaskId:{},请手动启动", xxlTaskId);
					}
					// 定时任务执行一次服务 单次任务不需要执行
					if (taskEntity.getType() == 2 && sdf.parse(taskEntity.getTaskStartTime()).getTime() <= new Date().getTime()) {
						String executorParam = "{\"taskId\":" + taskId + "}";
						result = this.xxlJobHttpInterface.mytrigger(Integer.parseInt(xxlTaskId), executorParam, null);
						if (result.getCode() != 200) {
							logger.error("执行xll-job任务失败，xxlTaskId:{},请手动启动", xxlTaskId);
						}
					}
				}
				else {
					throw new BaseException(ResultEnum.TASK_REGISTER_FAILED);
				}
				return CommonResponse.success(task.getId());
			}
		}
		catch (Exception e) {
			return CommonResponse.failed("新建任务失败" + e.getMessage());
		}
		return CommonResponse.success();
	}

	private void createTaskName(TaskEntity taskEntity) {
		if (StringUtils.isNotEmpty(taskEntity.getTaskName())) {
			return;
		}
		String modelName = taskEntity.getModelName();
		String datasetName = taskEntity.getDatasetName();
		String taskName = String.format("%s%s%s", modelName, datasetName, sdf2.format(new Date()));
		taskEntity.setTaskName(taskName);
	}

	private String getCron(TaskEntity taskEntity) throws Exception {
		String cron = "";
		String taskStartTime = taskEntity.getTaskStartTime();
		Date startDate = new Date();
		if (StringUtils.isNotEmpty(taskStartTime)) {
			startDate = sdf.parse(taskStartTime);
		}
		else {
			taskEntity.setTaskStartTime(sdf.format(startDate));
		}
		taskEntity.setNextEexcuteTime(sdf.format(startDate));
		Calendar cal = Calendar.getInstance();
		cal.setTime(startDate);
		int startYear = cal.get(Calendar.YEAR);// 获取年
		int month = cal.get(Calendar.MONTH) + 1;// 获取月
		int day = cal.get(Calendar.DAY_OF_MONTH);// 获取日
		int hour = cal.get(Calendar.HOUR_OF_DAY);// 获取时
		int min = cal.get(Calendar.MINUTE);
		;// 获取分
		Integer frequency = taskEntity.getFrequency();
		Integer unit = taskEntity.getUnit();
		if (taskEntity.getType() == 2) {
			switch (unit) {
				case 1:
					String cronDay = xxlJobInfo.getCronDay();
					cron = String.format(cronDay, min, hour, day, frequency, month);
				break;
				case 2:
					String cronMonth = xxlJobInfo.getCronMonth();
					cron = String.format(cronMonth, min, hour, day, frequency);
				break;
				case 3:
					String cronYear = xxlJobInfo.getCronYear();
					cron = String.format(cronYear, min, hour, day, month, frequency);
				break;
			}
		}
		else if (taskEntity.getType() == 1) {// 固定时间
			cal.add(Calendar.SECOND, 10);
			startYear = cal.get(Calendar.YEAR);// 获取年
			month = cal.get(Calendar.MONTH) + 1;// 获取月
			day = cal.get(Calendar.DAY_OF_MONTH);// 获取日
			hour = cal.get(Calendar.HOUR_OF_DAY);// 获取时
			min = cal.get(Calendar.MINUTE);
			;// 获取分
			int second = cal.get(Calendar.SECOND);// 获取秒
			String cronFixed = xxlJobInfo.getCronFixed();
			cron = String.format(cronFixed, second, min, hour, day, month, startYear);
		}
		return cron;
	}

	@Override
	public CommonResponse updateTask(TaskEntity taskEntity) {
		try {
			if (taskEntity.getDatasetId() == null || taskEntity.getDatasetId() <= 0) {
				return CommonResponse.failed("数据集ID不能为空!");
			}
			if (taskEntity.getModelId() == null || taskEntity.getModelId() <= 0) {
				return CommonResponse.failed("模型ID不能为空!");
			}
			if (taskEntity.getType() == 2) {
				if (taskEntity.getFrequency() == null || taskEntity.getFrequency() <= 0) {
					return CommonResponse.failed("任务执行频率不能为空!");
				}
				if (taskEntity.getUnit() == null || taskEntity.getUnit() <= 0) {
					return CommonResponse.failed("任务执行频率单位不能为空!");
				}
			}
			// 单次任务开始时间设置不能早于当前时间
			if (taskEntity.getType() == 1 && StringUtils.isNotEmpty(taskEntity.getTaskStartTime()) && sdf.parse(taskEntity.getTaskStartTime()).getTime() < new Date().getTime()) {
				return CommonResponse.failed(ResultEnum.TIME_IS_OUT_DATE);
			}
			// 任务名称唯一性校验
			LambdaQueryWrapper<Task> lambdaQueryWrapper = new LambdaQueryWrapper<>();
			lambdaQueryWrapper.eq(Task::getTaskName, taskEntity.getTaskName()).ne(Task::getId, taskEntity.getId());
			if (this.taskMapper.selectCount(lambdaQueryWrapper) > 0) {
				return CommonResponse.failed(ResultEnum.TASK_NAME_IS_EXIST);
			}

			JSONObject jSONObject = new JSONObject();
			jSONObject.put("taskId", taskEntity.getId());
			if (StringUtils.isNotEmpty(taskEntity.getTaskStartTime())) {
				jSONObject.put("taskStartTime", taskEntity.getTaskStartTime());
			}
			String excuteParam = JSON.toJSONString(jSONObject);

			Task task = this.baseMapper.selectById(taskEntity.getId());
			xxlJobInfo.setId(task.getXxlTaskId());
			xxlJobInfo.setJobDesc(taskEntity.getTaskName());
			xxlJobInfo.setAuthor("线索管理平台");
			String cron = this.getCron(taskEntity);
			xxlJobInfo.setScheduleConf(cron);
			xxlJobInfo.setExecutorParam(excuteParam);
			logger.info("调用xxl任务修改参数：{}", JSON.toJSONString(xxlJobInfo));
			ReturnT<String> result = this.xxlJobHttpInterface.myupdate(xxlJobInfo);
			if (result.getCode() != 200) {
				logger.error("更新xxl-job任务失败:{}", result.getMsg());
				return CommonResponse.failed("更新xxl-job任务失败," + result.getMsg());
			}
			// 修复缺陷JZPDTZFGJJ-430 任务终止了 需要再次触发启动
			// 启动服务
			result = this.xxlJobHttpInterface.mystart(task.getXxlTaskId());
			if (result.getCode() != 200) {
				logger.error("启动xll-job任务失败，xxlTaskId:{},请手动启动", task.getXxlTaskId());
			}
			// 更新表数据xxl_task_id
			LambdaUpdateWrapper<Task> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
			lambdaUpdateWrapper.eq(Task::getId, taskEntity.getId());
			lambdaUpdateWrapper.set(Task::getUpdateTime, new Date());
			if (StringUtils.isNotEmpty(taskEntity.getTaskName())) {
				lambdaUpdateWrapper.set(Task::getTaskName, taskEntity.getTaskName());
			}
			if (taskEntity.getModelId() != null && taskEntity.getModelId() > 0) {
				lambdaUpdateWrapper.set(Task::getModelId, taskEntity.getModelId());
			}
			if (StringUtils.isNotEmpty(taskEntity.getModelName())) {
				lambdaUpdateWrapper.set(Task::getModelName, taskEntity.getModelName());
			}
			if (taskEntity.getDatasetId() != null && taskEntity.getDatasetId() > 0) {
				lambdaUpdateWrapper.set(Task::getDatasetId, taskEntity.getDatasetId());
			}
			if (StringUtils.isNotEmpty(taskEntity.getDatasetName())) {
				lambdaUpdateWrapper.set(Task::getDatasetName, taskEntity.getDatasetName());
			}
			if (taskEntity.getType() != null && taskEntity.getType() > 0) {
				lambdaUpdateWrapper.set(Task::getType, taskEntity.getType());
			}
			if (StringUtils.isNotEmpty(taskEntity.getTaskStartTime())) {
				lambdaUpdateWrapper.set(Task::getTaskStartTime, taskEntity.getTaskStartTime());
			}
			/*
			 * if (StringUtils.isNotEmpty(taskEntity.getNextEexcuteTime()) && taskEntity.getType() == 2) { lambdaUpdateWrapper.set(Task::getNextExcuteTime,
			 * taskEntity.getNextEexcuteTime()); }
			 */
			if (taskEntity.getType() == 2) {
				ReturnT<String> returnT = this.xxlJobHttpInterface.nextTriggerTimeById(task.getXxlTaskId());
				if (returnT.getCode() == 200) {
					String content = returnT.getContent();
					// 单次任务下次执行时间时空值
					if (StringUtils.isNotEmpty(content)) {
						logger.info("doDataMinging任务taskId:{}获取到下次执行时间是NextExcuteTime:{}", taskEntity.getId(), content);
						lambdaUpdateWrapper.set(Task::getNextExcuteTime, content);
					}
				}
				lambdaUpdateWrapper.set(Task::getTaskStatus, TaskEnum.TASK_STATUS_RUNNING.getCode());
			}
			else if (taskEntity.getType() == 1) {
				lambdaUpdateWrapper.set(Task::getNextExcuteTime, null);
				// 任务开始时间大于系统时间 设置为运行中
				if (sdf.parse(taskEntity.getTaskStartTime()).getTime() >= new Date().getTime()) {
					lambdaUpdateWrapper.set(Task::getTaskStatus, TaskEnum.TASK_STATUS_RUNNING.getCode());
				}
				else {
					lambdaUpdateWrapper.set(Task::getTaskStatus, TaskEnum.TASK_STATUS_OVER.getCode());
				}
			}
			if (taskEntity.getFrequency() != null && taskEntity.getFrequency() > 0) {
				lambdaUpdateWrapper.set(Task::getFrequency, taskEntity.getFrequency());
			}
			if (taskEntity.getUnit() != null && taskEntity.getUnit() > 0) {
				lambdaUpdateWrapper.set(Task::getUnit, taskEntity.getUnit());
			}
			lambdaUpdateWrapper.set(Task::getCron, cron);
			int resultNum = this.taskMapper.update(null, lambdaUpdateWrapper);
			// int resultNum = taskMapper.updateTask(taskEntity);
			if (resultNum > 0) {
				return CommonResponse.success("修改任务成功");
			}
		}
		catch (Exception e) {
			e.printStackTrace();
			return CommonResponse.failed("修改任务失败" + e.getMessage());
		}
		return CommonResponse.success();
	}

	@Override
	public CommonResponse deleteTask(TaskEntity taskEntity) {
		try {
			// 查询任务Id
			Task task = this.baseMapper.selectById(taskEntity.getId());
			// 同时删除xxl-job平台任务
			ReturnT<String> result = this.xxlJobHttpInterface.myremove(task.getXxlTaskId());
			if (result.getCode() == 200) {
				logger.info("删除xxl-job任务成功XxlTaskId：{}", task.getXxlTaskId());
				int resultNum = this.baseMapper.deleteById(taskEntity.getId());
				if (resultNum > 0) {
					logger.info("调用xxl任务删除参数：{}", taskEntity.getId());
					this.xxlJobHttpInterface.myremove(taskEntity.getId());
					return CommonResponse.success("删除任务成功");
				}
			}
		}
		catch (Exception e) {
			e.printStackTrace();
			return CommonResponse.success("删除任务失败" + e.getMessage());
		}
		return CommonResponse.success();
	}

	@Override
	public CommonResponse queryTaskById(TaskEntity taskEntity) {
		try {
			Task task = this.baseMapper.selectById(taskEntity.getId());
			if (task != null) {
				return CommonResponse.success(task);
			}
		}
		catch (Exception e) {
			e.printStackTrace();
			return CommonResponse.success("查询任务失败" + e.getMessage());
		}
		return CommonResponse.success();
	}

	@Override
	public IPage<Task> queryTaskManageList(TaskManageListBo taskManageListBo) {
		try {

			IPage<Task> page = new Page<>(taskManageListBo.getPageNo(), taskManageListBo.getPageSize());
			IPage<Task> resultList = taskMapper.queryTaskManageList(page, taskManageListBo);
			List<Task> tasks = resultList.getRecords();
			for (Task t : tasks) {
				Integer taskId = t.getId();
				int exceptionNum = taskMapper.queryDetailCount(taskId);
				if (exceptionNum > 0) {
					t.setCanDelete(false);
				}
				else {
					t.setCanDelete(true);
				}
				if (t.getTaskStatus() != null && t.getTaskStatus() == 1) {
					t.setCanUpdate(false);
				}
				else {
					t.setCanUpdate(true);
				}
			}
			return resultList;
		}
		catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	@Override
	public IPage<TaskLogVo> queryTaskLogListByID(TaskManageListBo taskManageListBo, Boolean isDownLoad) {
		try {
			IPage<TaskManageListBo> page = new Page<>(taskManageListBo.getPageNo(), taskManageListBo.getPageSize());
			IPage<TaskLogVo> resultList = taskMapper.queryTaskLogListByID(page, taskManageListBo);
			List<TaskLogVo> list = resultList.getRecords();
			if (CollectionUtils.size(list) >= 2 && resultList.getCurrent() == 1) {
				list.get(1).setIsLast(true);
			}
			if (!isDownLoad) {
				list.forEach(taskLog -> {
					LambdaQueryWrapper<Clue> lambdaQueryWrapper = new LambdaQueryWrapper<>();
					lambdaQueryWrapper.eq(Clue::getTaskLogId, taskLog.getId());
					Clue clue = this.clueMapper.selectOne(lambdaQueryWrapper);
					if (null != clue) {
						taskLog.setClueName(clue.getClueName());
					}
				});
			}
			return resultList;
		}
		catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	@Override
	public IPage<TaskDetail> queryTaskDetailList(TaskManageListBo taskManageListBo) {
		try {
			IPage<TaskDetail> page = new Page<>(taskManageListBo.getPageNo(), taskManageListBo.getPageSize());
			IPage<TaskDetail> result = taskMapper.queryTaskDetailList(page, taskManageListBo);
			return result;
		}
		catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	@Override
	public Task getTaskById(Integer id) {
		return this.baseMapper.selectById(id);
	}

	@Override
	public CommonResponse mykill(Integer xxlLogId) {
		ReturnT<String> out = this.xxlJobHttpInterface.mykill(xxlLogId);
		if (null != out && out.getCode() == 200) {
			LambdaQueryWrapper<TaskLog> query = new LambdaQueryWrapper<>();
			query.eq(TaskLog::getXxlLogId, xxlLogId);
			TaskLog taskLog = this.taskLogMapper.selectOne(query);

			// 任务变成运行中止
			LambdaUpdateWrapper<Task> lambdaUpdateWrapper5 = new LambdaUpdateWrapper<Task>().set(Task::getTaskStatus, TaskEnum.TASK_STATUS_STOP.getCode()).set(Task::getUpdateTime, new Date())
			        .eq(Task::getId, taskLog.getTaskId());
			this.taskMapper.update(null, lambdaUpdateWrapper5);
			// 日志变成中断
			LambdaUpdateWrapper<TaskLog> lambdaUpdateWrapper3 = new LambdaUpdateWrapper<TaskLog>().set(TaskLog::getStatus, TaskEnum.TASK_RUN_STATUS_STOPPED.getCode())
			        .set(TaskLog::getTaskRunEndTime, new Date()).eq(TaskLog::getId, taskLog.getId());
			this.taskLogMapper.update(null, lambdaUpdateWrapper3);

			return CommonResponse.success(out.getContent());
		}
		return CommonResponse.failed("任务中止失败" + out.getContent());
	}
}
